package com.beantools.util.poutil;

import com.beantools.entity.EntityStorage;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.beantools.constants.MethodPrefix.*;
import static com.beantools.util.ObjectUtil.isNotNull;
import static com.beantools.util.StringUtil.*;

/**
 * 对于一个Javabean对象，其有属性和方法，调用者有时需要将属性转化为方法，
 * 有时需要将方法转化为属性。因为，这是一个将方法转化为属性的的工具类。
 *
 * @author baoya
 * @version 1.0
 * @since 1.1.0
 */
public class MethodUtil {


    /**
     * 这是静态方法，需要将set方法转化为属性名称，同时，首字母小写。
     *
     * @param method 待转化为属性的方法
     * @return 由方法名称转化的属性名称
     */
    public static String setterTransformProperty(Method method) {
        return methodTransformProperty(method, PREFIX_SET);
    }

    /**
     * 这是静态方法，需要将get方法，或is方法转化为属性。同时，首字母小写。
     *
     * @param method 待转化为属性的方法
     * @return 由方法名称转化的属性名称
     */
    public static String methodTransformProperty(Method method) {
        return methodTransformProperty(method, PREFIX_GET);
    }

    /**
     * 这是静态方法，需要将set方法，或is方法转化为属性。对于set方法，调用者需要截
     * 取set后的字符，同时将首字母转化为小写。对于is方法，调用者需要截取is后的字符，
     * 同时，将首字母转化为小写。
     *
     * @param flag   set表示截取set方法， get表示截取get方法
     * @param method 待转化为属性的方法
     * @return 由方法名称转化的属性名称
     */
    public static String methodTransformProperty(Method method, String flag) {
        boolean validateFlag = isNotNull(method)
                && isNotBlank(flag)
                && inAny(flag, PREFIX_SET, PREFIX_GET);
        if (!validateFlag) {
            return null;
        }
        String propertyName = null;
        String methodName = method.getName();
        if (methodName.startsWith(flag)) {
            propertyName = getPropertyName(methodName.substring(3));
        } else if (flag.equals(PREFIX_GET) && methodName.startsWith(PREFIX_IS)) {
            propertyName = getPropertyName(methodName.substring(2));
        }
        return propertyName;
    }

    /**
     * 该方法用来将去掉set、get、is方法之后的方法名的首字母小写，
     * 并返回响应首字母小写后的属性名。
     * <p>
     * 比如方法名getCustomerName()，去掉get之后的方法名为CustomerName
     * 程序需要将CustomerName转化为customerName。
     *
     * @param propertyName 属性名称，比如Name，CustomerName
     * @return 返回属性名称，比如customerName
     */
    public static String getPropertyName(String propertyName) {
        return isBlank(propertyName) ? null : (propertyName.substring(0, 1).toLowerCase() +
                (propertyName.length() > 1 ? propertyName.substring(1) : ""));
    }

    /**
     * 这是激活对象方法的方法。从实体存储器{@code storage}当中拿到对象方法后，
     * 该对象方法是{@code setter}方法。
     *
     * @param activeObj 待激活的对象
     * @param storage   对象的存储器
     * @param args      方法参数
     */
    public static <T> void invoke(T activeObj, EntityStorage storage, Object args) throws IllegalAccessException, InvocationTargetException {
        Method method = storage.getMethod();
        method.setAccessible(true);
        method.invoke(activeObj, args);
    }

    /**
     * 这是激活对象方法的方法。从实体存储器{@code storage}当中拿到对象方法后，
     * 该对象方法可以是{@code getter}、{@code is}方法，则激活方法为空
     *
     * @param activeObj 待激活的对象
     * @param storage   对象的存储器
     * @return 获取到的属性对象的值
     */
    public static <T> Object invoke(T activeObj, EntityStorage storage) throws IllegalAccessException, InvocationTargetException {
        Method method = storage.getMethod();
        method.setAccessible(true);
        return method.invoke(activeObj);
    }
}
